#ifndef MODULE_H_
#define MODULE_H_

#include <assert.h>
#include <iostream>
#include <map>
#include "types.h"

#include "settings.h"
#include "stat.h"

#include "../kernel/include/kernel/component.h"
#include "../kernel/include/kernel/manifold.h"

using namespace std;

#define IO_PORT std::multimap<timestamp_t, Mreq *>

/** Order here is important!!!  Determines the links between tiers in the protocol.
 *  See Sim::get_directory_module_index() to see why. */
class ModuleID {
public:
    int nodeID;
    module_t module_index;

    bool operator== (const ModuleID &mid);
    bool operator!= (const ModuleID &mid);

    Module* get_module();
};

class Module : public manifold::kernel::Component {
public:
    //TODO: make module name a C++ string
    char *name;
    IO_PORT *input_port;
    ModuleID moduleID;
    int clock_ratio;

    /* Number of requests that can be enqueued in one cycle whether in parallel or one by one eg: In case of core and cache it can be the maximum number of requests that may come in a cycle to the cache*/
    int num_ports;

	Module (ModuleID moduleID, const char *name, int clock_ratio = 1);
	virtual ~Module();

    bool has_waiting_mreq (void);
 	Mreq *read_input_port (void);
    void write_output_port (Mreq *mreq, timestamp_t resolve_time);
    bool output_port_writable();
    void enque (Mreq *mreq, timestamp_t resolve_time);
    void manifold_enque_now (int unused_id, Mreq *mreq);


    void *module_peek();

    bool tick_tock_p (void);

    //children need to implement
    virtual void tick (void) =0;
    virtual void tock (void) =0;
};

void print_id (const char *str, ModuleID mid);

#endif // MODULE_H_
